package com.prs.crm.view;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.SessionMap;
import org.courser.Util;
import org.courser.ui.PaginationHelper;
import org.courser.ui.PaginationSupport;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;

import com.opensymphony.xwork2.ActionContext;
import com.prs.crm.context.AppContext;

public class PaginationHelperImpl implements PaginationHelper {
	private int i = 0;

	@SuppressWarnings("unchecked")
	public DetachedCriteria createQuery(Class cls) {
		// System.out.println(1);
		DetachedCriteria criteria = DetachedCriteria.forClass(cls);
		List<criteriaData> inputconditons = new ArrayList<criteriaData>();
		ActionContext ctx = ActionContext.getContext();
		HttpServletRequest request = (HttpServletRequest) ctx
				.get(ServletActionContext.HTTP_REQUEST);
		i = 0;
		//System.out.println(i + "    1");
		String parameter = null;
		for (Enumeration<?> enums = request.getParameterNames(); enums
				.hasMoreElements();) {
			i = 1;
			//System.out.println(i + "    2");
			// System.out.println(2);
			try {
				parameter = enums.nextElement().toString();
				// System.out.println(3);
				if (parameter.indexOf("q_") == 0
						&& request.getParameter(parameter).trim().length() > 0) {
					// System.out.println(4);
					
					inputconditons.add(new criteriaData(parameter.substring(2),
							request.getParameter(parameter),
							getRequestMap(request.getQueryString())));
				}
			} catch (Exception ex) {
				ex.printStackTrace();
				continue;
			}
		}
		HashMap<String, String> aliasmap = new HashMap<String, String>();
		String queryfield = null;
		for (criteriaData data : inputconditons) {
			// System.out.println(5);
			
			try {
				// System.out.println(6);
				queryfield = createAlias(cls, criteria, data.field, null,
						aliasmap);
				
				if ((data.type == null || data.type.equals(String.class))
						&& (data.condition == null || data.condition
								.equals("eq"))) {
					// System.out.println(1);
					criteria.add(Restrictions.like(queryfield, "%" + data.value
							+ "%"));
				} else {// System.out.println(2);
					// criteria.add(Restrictions.eq(alias+queryfield,
					// ConvertUtils.convert(data.value, data.type)));
					criteria.add(createExpression(data.condition, queryfield,
							convert(data.value, data.type)));
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
		return criteria;
	}

	private Class<?> getPropertyClass(Class<?> cls, String propertyName) {
		PropertyDescriptor property = BeanUtils.getPropertyDescriptor(cls,
				propertyName);
		if (property != null)
			return property.getPropertyType();
		else
			return null;
	}

	private String createAlias(Class<?> cls, DetachedCriteria criteria,
			String field, String alias, HashMap<String, String> aliasmap) {
		int pos = field.indexOf(".");
		if (pos > 0) {
			String[] strary = field.split("\\.");
			String aliasname = strary[0];
			if (alias != null)
				aliasname = alias + "." + aliasname;
			Class<?> aliasClass = getPropertyClass(cls, aliasname);
			if (!aliasmap.containsKey(aliasname)) {
				criteria
						.createAlias(aliasname, aliasname.replaceAll("\\.", ""));
				aliasmap.put("aliasname", aliasname);
			}
			String other = field.substring(pos + 1);

			if (other.indexOf(".") > 0)
				return createAlias(aliasClass, criteria, other, aliasname,
						aliasmap);
			else
				return aliasname.replaceAll("\\.", "") + "." + other.trim();
		} else {
			return field;
		}
	}

	private HashMap<String, String> getRequestMap(String querystr) {
		HashMap<String, String> parahash = new HashMap<String, String>();
		if (querystr != null) {
			String[] up = null;
			String[] paras = querystr.split("&");
			for (String para : paras) {
				up = para.split("=");
				if (up.length > 1) {
					parahash.put(up[0], up[1]);
				}
			}
		}
		return parahash;
	}

	@SuppressWarnings("unchecked")
	private Object convert(Object value, Class cls) throws Exception {
		if (cls.equals(String.class))
			return value.toString();
		else if (cls.equals(java.util.Date.class))
			return Util.formatDateStr(value.toString());
		else if (cls.equals(Integer.class))
			return Integer.valueOf(value.toString());
		else if (cls.equals(Double.class))
			return Double.valueOf(value.toString());
		else if (cls.equals(Short.class))
			return Short.valueOf(value.toString());
		else if (cls.equals(Long.class))
			return Long.valueOf(value.toString());
		else if (cls.equals(Float.class))
			return Float.valueOf(value.toString());
		return value;
	}

	private Criterion createExpression(String condition, String field,
			Object value){
		if (condition == null || condition.equals("eq"))
			return Restrictions.eq(field, value);
		else if (condition.equals("gt"))
			return Restrictions.gt(field, value);
		else if (condition.equals("ge"))
			return Restrictions.ge(field, value);
		else if (condition.equals("lt"))
			return Restrictions.lt(field, value);
		else if (condition.equals("le"))
			return Restrictions.le(field, value);
		else if (condition.equals("ne"))
			return Restrictions.ne(field, value);
		else if (condition.equals("region") && value instanceof Date) {
			try {
				return Restrictions.and(Restrictions.ge(field, value),Restrictions.lt(field, Util.addTimeByDay((Date) value,1)));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	private String getStorKey(PaginationSupport page, HttpServletRequest request) {
		return request.getRequestURI() + ".page";
	}

	@SuppressWarnings("unchecked")
	private void memoryPage(PaginationSupport page) {
		SessionMap session = AppContext.getSessionMap();
		HttpServletRequest request = AppContext.getHttpServletRequest();
		String key = getStorKey(page, request);
		String param = request.getQueryString();
		if (param != null && param.indexOf(".currentPage") > 0) {
			session.put(key, page.getCurrentPage());
		} else if (page.getCurrentPage() == 0 && session.get(key) != null) {
			if (i == 1) {
			
				page.setCurrentPage((Integer) session.get(key));
			}
		}

	}

	public PaginationSupport prepare(PaginationSupport page) {
		if (page == null) {
			page = new PaginationSupport();
		}
		memoryPage(page);
		//System.out.println(i + "    3");
		if (page.getCurrentPage() > 0 && i == 1){
		//	System.out.println("asdf");
			page.setStartIndex(page.getCurrentPage() * page.getPageSize());}

		return page;
	}

	public PaginationSupport prepare(PaginationSupport page, int pagesize) {
		if (page == null)
			page = new PaginationSupport();
		page.setPageSize(pagesize);
		memoryPage(page);
		if (page.getCurrentPage() > 0)
			page.setStartIndex(page.getCurrentPage() * page.getPageSize());
		return page;
	}

	class criteriaData {
		private String field;
		private Class<?> type;
		private Object value;
		private String condition;

		public void setField(String field) {
			this.field = field;
		}

		public String getField() {
			return field;
		}

		public void setValue(Object value) {
			this.value = value;
		}

		public Object getValue() {
			return value;
		}

		@SuppressWarnings("unchecked")
		public void setType(Class type) {
			this.type = type;
		}

		@SuppressWarnings("unchecked")
		public Class getType() {
			return type;
		}

		public criteriaData(String srcid, String field, Map<String, String> req) {
			this.create(srcid, field, req);
		}

		public void create(String srcid, String name, Map<String, String> req) {
			try {
				HttpServletRequest request = (HttpServletRequest) ActionContext
						.getContext().get(ServletActionContext.HTTP_REQUEST);
				this.field = name;
				String typepra = name + "_" + srcid + "_type";
				String conditionpra = name + "_" + srcid + "_condition";
				request.setAttribute("q_" + srcid, field);
				if (req.get(typepra) != null && req.get(typepra).length() > 0) {
					String typestr = req.get(typepra);
					String ltypestr = typestr.toLowerCase();
					if (ltypestr.equals("string"))
						type = String.class;
					else if (ltypestr.equals("short"))
						type = Short.class;
					else if (ltypestr.equals("long"))
						type = Long.class;
					else if (ltypestr.equals("double"))
						type = Double.class;
					else if (ltypestr.equals("float"))
						type = Float.class;
					else if (ltypestr.equals("int"))
						type = Integer.class;
					else if (ltypestr.equals("date"))
						type = java.util.Date.class;
					else {
						type = Class.forName(typestr);
					}
				}
				if (type == null)
					type = String.class;
				if (req.get(conditionpra) != null
						&& req.get(conditionpra).length() > 0) {
					this.condition = req.get(conditionpra);
					request.setAttribute(conditionpra, this.condition);
				}
				request.setAttribute(typepra, type);
				String vpara = field + "_" + srcid + "_value";
				if (req.get(vpara) != null && req.get(vpara).length() > 0) {
					this.value = Util.convertRequestParameter(req.get(vpara));
					ActionContext.getContext().getValueStack().set(
							vpara.replaceAll("\\.", "_"), value);
				}

			} catch (Exception e) {
			}

		}

		public void setCondition(String condition) {
			this.condition = condition;
		}

		public String getCondition() {
			return condition;
		}
	}
}